
package com.borqs.music.ui;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.app.TimePickerDialog;
import android.app.TimePickerDialog.OnTimeSetListener;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.provider.MediaStore;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TabHost;
import android.widget.TabHost.OnTabChangeListener;
import android.widget.TabHost.TabContentFactory;
import android.widget.TimePicker;

import com.borqs.music.MediaPlaybackService;
import com.borqs.music.R;
import com.borqs.music.executor.MusicExecutor;
import com.borqs.music.executor.Task;
import com.borqs.music.executor.TaskAdapter;
import com.borqs.music.executor.TaskListener;
import com.borqs.music.model.VersionInfo;
import com.borqs.music.tasks.QueryVersionInfoTask;
import com.borqs.music.ui.FixedEntryListActivity.CategoryAdapter;
import com.borqs.music.ui.FixedEntryListActivity.ListViewItem;
import com.borqs.music.ui.online.PersonalArtistAlbumActivity;
import com.borqs.music.ui.online.PersonalMusicListActivity;
import com.borqs.music.util.AccountUtils;
import com.borqs.music.util.MusicUtils;
import com.borqs.music.util.MusicUtils.ServiceToken;
import com.borqs.music.util.MusicUtils.TypeDefs;
import com.borqs.music.util.MyLogger;
import com.borqs.music.util.StopMusicReceiver;

public class MyMusicActivity extends GestureTabActivity implements TabContentFactory,
        ServiceConnection, MusicUtils.Defs {
    private static final MyLogger logger = MyLogger.getLogger("MyMusicActivity");
    public final static String ONLINE_TAB_TAG = "online_tab";
    public final static String LOCAL_TAB_TAG = "local_tab";
    private static boolean mIsInitVersionChecked = false;
    private ServiceToken mToken;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.requestWindowFeature(Window.FEATURE_NO_TITLE);
        super.onCreate(savedInstanceState);
        mToken = MusicUtils.bindToService(this, this);
        MusicUtils.addNowPlayingListener(this);
        if (MusicUtils.isAccessServerAvailable(this)) {
            SignupUploadActivity.selfCheck(getApplicationContext());
            if (!mIsInitVersionChecked) {
                mIsInitVersionChecked = true;
                String ticket = AccountUtils.getUserData(this,
                        AccountUtils.BORQS_ACCOUNT_OPTIONS_KEY_SESSION);
                QueryVersionInfoTask task = new QueryVersionInfoTask(mTaskListener, ticket);
                MusicExecutor.getInstance().execute(task);
            }
            findViewById(R.id.title_bar).setVisibility(View.GONE);
        } else {
            ImageView backImg = (ImageView) findViewById(R.id.title_back);
            backImg.setBackgroundResource(R.drawable.app_music);
            findViewById(R.id.title_bar).setVisibility(View.VISIBLE);
        }
    }

    @Override
    protected void onResume() {
        super.onResume();

        setTitle(R.string.app_name);
        IntentFilter f = new IntentFilter();
        f.addAction(MediaPlaybackService.META_CHANGED);
        f.addAction(MediaPlaybackService.QUEUE_CHANGED);
        registerReceiver(mTrackListListener, f);
        mTrackListListener.onReceive(null, null);
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(mTrackListListener);
    }

    @Override
    protected void onDestroy() {
        if (mToken != null) {
            MusicUtils.unbindFromService(mToken);
        }
        super.onDestroy();
    }

    private static final int MAN_SCAN = 0;
    private static final int SLEEP_MODE = 1;
    private static final int USER_SETTING = 2;
    private final static int REQ_SYSTEM_SETTINGS = 4;

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        // menu.add(0, MAN_SCAN, 0, R.string.menu_manual_scan);
        menu.add(0, SLEEP_MODE, 0, R.string.menu_sleep_mode);
        if (MusicUtils.isAccessServerAvailable(this)) {
            menu.add(0, USER_SETTING, 0, R.string.menu_user_setting);
        }
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // TODO This Intent defined in Intent.java but be hided in SDK.
        // We should use Intent.ACTION_MEDIA_SCANNER_SCAN_DIR if SDK open it.
        String ACTION_MEDIA_SCANNER_SCAN_DIR = "android.intent.action.MEDIA_SCANNER_SCAN_DIR";
        switch (item.getItemId()) {
            case MAN_SCAN:
                File dirFile = Environment.getExternalStorageDirectory();
                if (dirFile.exists()) {
                    Intent scanIntent = new Intent(ACTION_MEDIA_SCANNER_SCAN_DIR);
                    scanIntent.setData(Uri.fromFile(dirFile));
                    sendBroadcast(scanIntent);
                }
                return true;
            case SLEEP_MODE:
                OnTimeSetListener callBack = new OnTimeSetListener() {
                    @Override
                    public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
                        if (hourOfDay > 0 || minute > 0) {
                            int lastedTime = (hourOfDay * 60) + minute;
                            Intent intent = new Intent(
                                    StopMusicReceiver.ACTION_INIT_STOP_PLAY);
                            intent.putExtra(StopMusicReceiver.EXTRA_LASTED_TIME,
                                    lastedTime);
                            sendBroadcast(intent);
                        }
                    }
                };
                Dialog d = new TimePickerDialog(this, callBack, 1, 0, true);
                d.setTitle(R.string.dialog_sleep_tile);
                d.show();
                break;
            case USER_SETTING:
                Intent intent = new Intent(this, SettingsActivity.class);
                startActivityForResult(intent, REQ_SYSTEM_SETTINGS);
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    private BroadcastReceiver mTrackListListener = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            MusicUtils.updateNowPlaying(MyMusicActivity.this);
        }
    };

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        MusicUtils.updateNowPlaying(this);
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        finish();
    }

    @Override
    protected void addTabs() {
        TabHost tabHost = getTabHost();
        tabHost.setOnTabChangedListener(new OnTabChangeListener() {
            @Override
            public void onTabChanged(String tabId) {
                if (tabId.equals(LOCAL_TAB_TAG)) {
                    findViewById(R.id.bg_cloud).setVisibility(View.GONE);
                } else {
                    findViewById(R.id.bg_cloud).setVisibility(View.VISIBLE);
                }
            }
        });
        // Add Local Tab
        View localIndicator = createIndicator(R.string.my_local_music, true);
        tabHost.addTab(tabHost.newTabSpec(LOCAL_TAB_TAG).setIndicator(localIndicator)
                .setContent(this));
        if (MusicUtils.isAccessServerAvailable(this)) {
            tabHost.getTabWidget().setVisibility(View.VISIBLE);
            // Add Online Tab
            View onlineIndicator = createIndicator(R.string.my_online_music, false);
            tabHost.addTab(tabHost.newTabSpec(ONLINE_TAB_TAG).setIndicator(onlineIndicator)
                    .setContent(this));
        } else {
            tabHost.getTabWidget().setVisibility(View.GONE);
        }
    }

    @Override
    public int getTabCount() {
        if (MusicUtils.isAccessServerAvailable(this)) {
            return 2;
        } else {
            return 1;
        }
    }

    @Override
    public View createTabContent(String tag) {
        ListView view = null;
        CategoryAdapter adapter = null;
        if (LOCAL_TAB_TAG.equals(tag)) {
            view = (ListView) findViewById(R.id.local_list);
            adapter = new CategoryAdapter(this, createLocalListItem());
            view.setOnItemClickListener(localItemListener);
            view.setAdapter(adapter);
        } else if (ONLINE_TAB_TAG.equals(tag)) {
            view = (ListView) findViewById(R.id.online_list);
            adapter = new CategoryAdapter(this, createOnlineListItem());
            view.setOnItemClickListener(onlineItemListener);
            view.setAdapter(adapter);
            view.setVisibility(View.VISIBLE);
        }
        return view;
    }

    private OnItemClickListener localItemListener = new OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            Intent intent = new Intent(Intent.ACTION_PICK);

            switch ((int) id) {
                // local event
                case LOCAL_RANDOM: {
                    Cursor cursor = MusicUtils.query(MyMusicActivity.this,
                            MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                            new String[] {
                                MediaStore.Audio.Media._ID
                            },
                            MediaStore.Audio.Media.IS_MUSIC + "=1", null,
                            MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
                    if (cursor != null) {
                        MusicUtils.shuffleAll(MyMusicActivity.this, cursor);
                        cursor.close();
                    }
                    return;
                }
                case LOCAL_ALL: {
                    intent.setDataAndType(Uri.EMPTY, TypeDefs.TRACK);
                    break;
                }
                case LOCAL_SINGER: {
                    intent.setDataAndType(Uri.EMPTY, TypeDefs.ARTIST_ALBUM);
                    break;
                }
                case LOCAL_ALBUM: {
                    intent.setDataAndType(Uri.EMPTY, TypeDefs.ALBUM);
                    break;
                }
                case LOCAL_DIRECTORY: {
                    intent.setDataAndType(Uri.EMPTY, TypeDefs.DIRECTORY);
                    break;
                }
                case LOCAL_PLAYLIST: {
                    intent.setDataAndType(Uri.EMPTY, TypeDefs.PLAYLIST);
                    break;
                }
                default:
                    break;
            }

            startActivity(intent);
        }
    };


    private OnItemClickListener onlineItemListener = new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            Intent intent = new Intent(Intent.ACTION_PICK);

            switch ((int) id) {
                case ONLINE_ALL: {
                    intent.setClass(MyMusicActivity.this, PersonalMusicListActivity.class);
                    intent.setDataAndType(Uri.EMPTY, TypeDefs.ONLINE_PERSONAL_TRACK);
                    break;
                }
                case ONLINE_SINGER: {
                    intent.setClass(MyMusicActivity.this,
                            PersonalArtistAlbumActivity.class);
                    intent.setDataAndType(Uri.EMPTY, TypeDefs.ONLINE_PERSONAL_ARTIST);
                    break;
                }
                case ONLINE_ALBUM: {
                    intent.setClass(MyMusicActivity.this,
                            PersonalArtistAlbumActivity.class);
                    intent.setDataAndType(Uri.EMPTY, TypeDefs.ONLINE_PERSONAL_ALBUM);
                    break;
                }
                case ONLINE_FAVORITE: {
                    intent.setClass(MyMusicActivity.this,
                            PersonalMusicListActivity.class);
                    intent.setDataAndType(Uri.EMPTY, TypeDefs.ONLINE_PERSONAL_FAVORITE);
                }
                default:
                    break;
            }

            if (!MusicUtils.isNetworkEnabled(MyMusicActivity.this)) {
                Dialog dialog = MusicUtils.getCheckNetworkDialog(MyMusicActivity.this);
                dialog.show();
            } else if (MusicUtils.checkBorqsAccount(MyMusicActivity.this)) {
                startActivity(intent);
            }
        }
    };

    private static final int LOCAL_RANDOM = 0;
    private static final int LOCAL_ALL = 2;
    private static final int LOCAL_SINGER = 3;
    private static final int LOCAL_ALBUM = 4;
    private static final int LOCAL_DIRECTORY = 5;
    private static final int LOCAL_PLAYLIST = 6;
    private static final int ONLINE_ALL = 7;
    private static final int ONLINE_SINGER = 8;
    private static final int ONLINE_ALBUM = 9;
    private static final int ONLINE_FAVORITE = 10;

    private static List<ListViewItem> createLocalListItem() {
        List<ListViewItem> items = new ArrayList<ListViewItem>();
        ListViewItem item1 = new ListViewItem();
        item1.id = LOCAL_RANDOM;
        item1.textResId = R.string.list_item_random;
        item1.iconResId = R.drawable.ic_list_random;
        items.add(item1);

        ListViewItem item3 = new ListViewItem();
        item3.id = LOCAL_ALL;
        item3.textResId = R.string.list_item_all_song;
        item3.iconResId = R.drawable.ic_list_allsongs;
        items.add(item3);

        ListViewItem item4 = new ListViewItem();
        item4.id = LOCAL_SINGER;
        item4.textResId = R.string.list_item_singer;
        item4.iconResId = R.drawable.ic_list_artist;
        items.add(item4);

        ListViewItem item5 = new ListViewItem();
        item5.id = LOCAL_ALBUM;
        item5.textResId = R.string.list_item_album;
        item5.iconResId = R.drawable.ic_list_album;
        items.add(item5);

        ListViewItem item6 = new ListViewItem();
        item6.id = LOCAL_DIRECTORY;
        item6.textResId = R.string.list_item_directory;
        item6.iconResId = R.drawable.ic_list_directory;
        items.add(item6);

        ListViewItem item7 = new ListViewItem();
        item7.id = LOCAL_PLAYLIST;
        item7.textResId = R.string.list_item_playlist;
        item7.iconResId = R.drawable.ic_list_playlist;
        items.add(item7);

        return items;
    }

    private static List<ListViewItem> createOnlineListItem() {
        List<ListViewItem> items = new ArrayList<ListViewItem>();

        ListViewItem item1 = new ListViewItem();
        item1.id = ONLINE_ALL;
        item1.textResId = R.string.list_item_all_song;
        item1.iconResId = R.drawable.ic_list_allsongs;
        items.add(item1);

        ListViewItem item2 = new ListViewItem();
        item2.id = ONLINE_SINGER;
        item2.textResId = R.string.list_item_singer;
        item2.iconResId = R.drawable.ic_list_artist;
        items.add(item2);

        ListViewItem item3 = new ListViewItem();
        item3.id = ONLINE_ALBUM;
        item3.textResId = R.string.list_item_album;
        item3.iconResId = R.drawable.ic_list_album;
        items.add(item3);

        ListViewItem item4 = new ListViewItem();
        item4.id = ONLINE_FAVORITE;
        item4.textResId = R.string.list_item_my_favorite;
        item4.iconResId = R.drawable.ic_list_favorite;
        items.add(item4);

        return items;
    }

    private TaskListener mTaskListener = new TaskAdapter() {
        public void onDone(Task task) {
            Message msg = mHandler.obtainMessage(MSG_GET_VERSION);
            msg.obj = task.getResult();
            mHandler.sendMessageDelayed(msg, 500);
        };
    };

    private static final int MSG_GET_VERSION = 1;
    private static final int MSG_UPDATE_MAX = 2;
    private static final int MSG_UPDATE_PROGRESS = 3;
    private static final int MSG_DOWNLOAD_DONE = 4;
    private Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_GET_VERSION:
                    VersionInfo version = (VersionInfo) msg.obj;
                    if (checkVersionInfo(version)) {
                        double downloadedSize = (double) version.getFileSize() / 1024 / 1024;
                        Bundle bundle = new Bundle();
                        bundle.putParcelable(BUNDLE_KEY_VERSION, version);
                        bundle.putDouble(BUNDLE_KEY_DOWNLOADSIZE, downloadedSize);
                        showDialog(DIALOG_PROMPT_NEW_VERSION, bundle);
                    }
                    break;
                case MSG_UPDATE_MAX:
                    mProgressDialog.setMax(msg.arg1);
                    break;
                case MSG_UPDATE_PROGRESS:
                    mProgressDialog.setProgress(msg.arg1);
                    break;
                case MSG_DOWNLOAD_DONE:
                    dismissDialog(DIALOG_DOWNLOAD);
                    break;
            }
        }
    };

    private static final String BUNDLE_KEY_VERSION = "version";
    private static final String BUNDLE_KEY_DOWNLOADSIZE = "downloadsize";

    private boolean checkVersionInfo(VersionInfo version) {
        try {
            PackageInfo pinfo = getPackageManager().getPackageInfo(getPackageName(),
                    PackageManager.PERMISSION_GRANTED);
            if (version.getVersionCode() > pinfo.versionCode) {
                return true;
            }
        } catch (NameNotFoundException e) {
            logger.e(e.getMessage());
        }
        return false;
    }

    private void downloadNewVersion(final VersionInfo version) {
        File dir = new File(Environment.getExternalStorageDirectory().getPath(),
                "borqs/borqsmusic/apk/");
        if (!dir.exists()) {
            dir.mkdirs();
        }
        final File file = new File(dir.getAbsolutePath(),
                "borqsmusic_" + version.getVersionCode() + ".apk");
        if (file.isFile() && file.exists()) {
            if (file.length() == version.getFileSize()) {
                startInstallAPKActivity(file);
                return;
            } else {
                file.delete();
            }
        }

        showDialog(DIALOG_DOWNLOAD);
        new Thread() {
            @Override
            public void run() {
                try {
                    file.createNewFile();
                    FileOutputStream fileOutput = new FileOutputStream(
                            file);
                    URL url = new URL(version.getFileUrl());
                    HttpURLConnection con = (HttpURLConnection) url
                            .openConnection();
                    con.setRequestMethod("GET");
                    con.setDoOutput(true);
                    con.connect();

                    InputStream inputStream = con.getInputStream();
                    int totalSize = con.getContentLength();
                    Message msg = mHandler.obtainMessage(MSG_UPDATE_MAX);
                    msg.arg1 = totalSize / 1024;
                    mHandler.sendMessage(msg);

                    int downloadedSize = 0;
                    byte[] buffer = new byte[1024 * 4];
                    int bufferLength = 0;
                    while ((bufferLength = inputStream.read(buffer)) > 0) {
                        fileOutput.write(buffer, 0, bufferLength);
                        downloadedSize += bufferLength;
                        mHandler.removeMessages(MSG_UPDATE_PROGRESS);
                        msg = mHandler.obtainMessage(MSG_UPDATE_PROGRESS);
                        msg.arg1 = downloadedSize / 1024;
                        mHandler.sendMessage(msg);
                    }
                    fileOutput.close();
                    inputStream.close();
                    con.disconnect();
                    if (downloadedSize >= totalSize) {
                        msg = mHandler.obtainMessage(MSG_DOWNLOAD_DONE);
                        mHandler.sendMessage(msg);
                        startInstallAPKActivity(file);
                    } else {
                        file.delete();
                    }

                } catch (MalformedURLException e) {
                    logger.e(e.getMessage());
                } catch (ProtocolException e) {
                    logger.e(e.getMessage());
                } catch (IOException e) {
                    logger.e(e.getMessage());
                } finally {
                    Message msg = mHandler.obtainMessage(MSG_DOWNLOAD_DONE);
                    mHandler.sendMessage(msg);
                }
            }
        }.start();

    }

    private void startInstallAPKActivity(File file) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.fromFile(file),
                "application/vnd.android.package-archive");
        startActivity(intent);
    }

    private final static int DIALOG_SCANNING = 1;
    private final static int DIALOG_PROMPT_NEW_VERSION = 2;
    private final static int DIALOG_DOWNLOAD = 3;
    private ProgressDialog mProgressDialog;

    @Override
    protected Dialog onCreateDialog(int id, final Bundle args) {
        switch (id) {
            case DIALOG_SCANNING:
                // create Dialog for scanning media
                ProgressDialog pDialog = new ProgressDialog(this);
                pDialog.setIcon(android.R.drawable.ic_dialog_info);
                pDialog.setTitle(R.string.dialog_scanning_title);
                pDialog.setMessage(getString(R.string.dialog_scanning_message));
                pDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
                return pDialog;
            case DIALOG_PROMPT_NEW_VERSION:
                return new AlertDialog.Builder(MyMusicActivity.this)
                        .setIcon(R.drawable.dialog_question)
                        .setTitle(R.string.dialog_new_version_tile)
                        .setMessage(
                                getString(R.string.dialog_new_version_message,
                                        args.getDouble(BUNDLE_KEY_DOWNLOADSIZE)))
                        .setNeutralButton(android.R.string.ok,
                                new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        downloadNewVersion((VersionInfo) args
                                                .getParcelable(BUNDLE_KEY_VERSION));
                                    }
                                }).setNegativeButton(android.R.string.cancel, null).create();
            case DIALOG_DOWNLOAD:
                mProgressDialog = new ProgressDialog(this);
                mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                mProgressDialog.setIcon(android.R.drawable.ic_dialog_info);
                mProgressDialog.setTitle(R.string.dialog_download_title);
                mProgressDialog.setMessage(getString(R.string.dialog_download_message));
                mProgressDialog.setCancelable(true);
                mProgressDialog.setProgress(0);
                return mProgressDialog;
            default:
                break;
        }
        return super.onCreateDialog(id, args);
    }
}
